package test.test.test;

import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.engine.camera.hud.controls.BaseOnScreenControl;
import org.anddev.andengine.engine.camera.hud.controls.DigitalOnScreenControl;
import org.anddev.andengine.engine.camera.hud.controls.BaseOnScreenControl.IOnScreenControlListener;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.entity.IEntity;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier.IPathModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.util.constants.Constants;
import org.anddev.andengine.util.modifier.IModifier;
import org.anddev.andengine.util.modifier.ease.EaseLinear;
import org.anddev.andengine.util.path.ITiledMap;
import org.anddev.andengine.util.path.astar.AStarPathFinder;

//This class is used primarily for organization
public class UI extends Game{
	
	public UI() {		
	}
	
	//**********************************************************************************************************************
	
	public static void GeneralUI(boolean TouchEnabled, boolean DigitalEnabled) {
		if (DigitalEnabled) {

			// Add the control
			mDigitalOnScreenControl = new DigitalOnScreenControl(0, CAMERA_HEIGHT
					- mOnScreenControlBaseTextureRegion.getHeight(), mBoundChaseCamera,
					mOnScreenControlBaseTextureRegion, mOnScreenControlKnobTextureRegion, 0.003f,
					new IOnScreenControlListener() {
						//Number of tiles the sprite will go when tapping the DPad
						//**WARNING** Messes up collisions if not 1
						int TileNumber = 1;

						public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl,
								final float pValueX, final float pValueY) {
							// Set the correct walking animation
							if (A_path == null) {

								float moveToXTile = player.getX() + TileNumber * TILE_WIDTH * pValueX;
								float moveToYTile = player.getY() + TileNumber * TILE_HEIGHT * pValueY;

								//sets the Dpad limits to within the Tiled map
								if (moveToXTile < TMXMapLayer.getWidth() && moveToYTile < TMXMapLayer.getHeight()
										&& moveToXTile >= 0 && moveToYTile >= 0) {
									//Sets the path to take from the values obtained by DPad
									walkTo(moveToXTile, moveToYTile, mScene);
								}

							}

						}

					});

			mDigitalOnScreenControl.getControlBase().setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
			mDigitalOnScreenControl.getControlBase().setAlpha(0.5f);
			mDigitalOnScreenControl.getControlBase().setScaleCenter(0, 128);
			mDigitalOnScreenControl.getControlBase().setScale(1.25f);
			mDigitalOnScreenControl.getControlKnob().setScale(1.25f);
			mDigitalOnScreenControl.getControlKnob().setAlpha(0.5f);
			mDigitalOnScreenControl.refreshControlKnobPosition();

			//This gets attached in Attach assets when the GeneralUI is called
			mScene.setChildScene(mDigitalOnScreenControl);
			mDigitalOnScreenControl.setIgnoreUpdate(true);
		}



		// These must be defined for the findpath() method to work
		final ITiledMap<TMXLayer> mTiledMap = new ITiledMap<TMXLayer>() {

			// Pretty self explanatory
			public int getTileColumns() {
				return mTMXTiledMap.getTileColumns();
			}

			// Pretty self explanatory
			public int getTileRows() {
				return mTMXTiledMap.getTileRows();
			}

			// Lets you customize what blocks you want to be considered blocked
			public boolean isTileBlocked(TMXLayer pTile, final int pToTileColumn, final int pToTileRow) {

				// Tile in the A* Path
				TMXTile blocked = TMXMapLayer.getTMXTile(pToTileColumn, pToTileRow);

				// Returns true if the tile in the A* Path is contained in the Arraylist CollideTiles
				if (CollideTiles.contains(blocked)) {
					return true;

				}
				// Return false by default = no tiles blocked
				return false;
			}

			// This is the key function to understand for AStar pathing Returns the cost of the next tile in the path
			public float getStepCost(final TMXLayer pTile, final int pFromTileColumn, final int pFromTileRow,
					final int pToTileColumn, final int pToTileRow) {
				// grab the first property from a tile at
				// pToTileColumn x pToTileRow
				// TMXProperty cost =
				// TMXMapLayer.getTMXTile(pToTileColumn,
				// pToTileRow).getTMXTileProperties(mTMXTiledMap).get(0);
				// Gets the value of the string
				// return Float.parseFloat(cost.getValue());
				return 0;

			}

			// If the tile is processed by findpath(), any extra
			// code you might want goes here
			public void onTileVisitedByPathFinder(int pTileColumn, int pTileRow) {
				// Do Nothing
			}
		};

		// Declare the AStarPathFinder
		// First Param: above ITiledMap
		// Second Param: Max Search Depth - Care, if this is too
		// small your program will crash
		// Third Param: allow diagonal movement or not
		// Fourth Param: Heuristics you want to use in the A* algorithm(optional)
		finder = new AStarPathFinder<TMXLayer>(mTiledMap, 15, false);

		//TODO: Make sure this doesn't cause memory leaks, because it is called multiple times and is never removed
		//Allows the screen to be touched every second by reseting a boolean 
		mScene.registerUpdateHandler(new TimerHandler(0.75f, true, new ITimerCallback() {
			public void onTimePassed(final TimerHandler pTimerHandler) {
				//Sets the bool flag, that controls the touch response, to true
				TouchOnce = true;
			}
		}));

	}

	//***********************************************************************************************************************

	public static void walkTo(final float pX, final float pY, Scene pScene) {

		// If the user is touching the screen Puts the touch events into an array
		final float[] pToTiles = pScene.convertLocalToSceneCoordinates(pX, pY);

		// Gets the tile at the touched location
		final TMXTile tmxTilePlayerTo = TMXMapLayer.getTMXTileAt(pToTiles[Constants.VERTEX_INDEX_X],
				pToTiles[Constants.VERTEX_INDEX_Y]);

		/*********/
		// if is walking and there is a A_path ******************
		if (isWalking == true && A_path != null) {
			walkToNextWayPoint(pX, pY, pScene);
		} else if (A_path == null) {
			// Sets the A* path from the player location to the touched location.
			A_path = finder.findPath(TMXMapLayer, 20,
			// Sprite's initial tile location
					playerLocationTile.getTileColumn(), playerLocationTile.getTileRow(),
					// Sprite's final tile location
					tmxTilePlayerTo.getTileColumn(), tmxTilePlayerTo.getTileRow());

			// The path with the above parameters should be saved
			loadPathFound();
		}
	}

	//***********************************************************************************************************************

	private static void walkToNextWayPoint(final float pX, final float pY, final Scene pScene) {

		player.unregisterEntityModifier(mMoveModifier);

		// mPathTemp is another global PathModifier
		player.unregisterEntityModifier(mPathTemp);

		final Path lPath = mCurrentPath.deepCopy();
		// create a new path with length 2 from current sprite position to next
		// original path waypoint
		final Path path = new Path(2);
		path.to(player.getX(), player.getY()).to(lPath.getCoordinatesX()[mWaypointIndex + 1],
				lPath.getCoordinatesY()[mWaypointIndex + 1]);

		// recalculate the speed.TILE_WIDTH is the tmx tile width, use yours
		//Adjust the speed for different control options
		float TileSpeed = 0;
		if (Options.TouchEnabled) {
			TileSpeed = path.getLength() * TOUCH_SPEED / (TILE_WIDTH);
		} else if (Options.DigitalControlEnabled) {
			TileSpeed = path.getLength() * DIGITAL_SPEED / (TILE_WIDTH);
		}

		// Create the modifier of this subpath
		mPathTemp = new PathModifier(TileSpeed, path, new IEntityModifierListener() {

			public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {

			}

			public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {

			}
		}, new IPathModifierListener() {

			public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity,
					int pWaypointIndex) {

			}

			public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity, int pWaypointIndex) {

			}

			public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {

			}

			public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
				if (Options.TouchEnabled) {
					player.stopAnimation();
				}
				A_path = null;
				walkTo(pX, pY, pScene);
			}
		});

		player.registerEntityModifier(mPathTemp);
	}

	//***********************************************************************************************************************

	private static void loadPathFound() {

		if (A_path != null) {
			// Global var
			mCurrentPath = new Path(A_path.getLength());
			int tilewidth = mTMXTiledMap.getTileWidth();
			int tileheight = mTMXTiledMap.getTileHeight();

			for (int i = 0; i < A_path.getLength(); i++) {
				mCurrentPath.to(A_path.getTileColumn(i) * tilewidth, A_path.getTileRow(i) * tileheight);
			}
			doPath();
		}
	}

	//***********************************************************************************************************************

	private static void doPath() {

		//Adjust the speed for different control options
		float Speed = 0;
		if (Options.TouchEnabled) {
			Speed = TOUCH_SPEED;
		} else if (Options.DigitalControlEnabled) {
			Speed = DIGITAL_SPEED;
		}

		// Create this mMoveModifier as Global, there is TOUCH_SPEED too -> player
		// speed
		mMoveModifier = new PathModifier(Speed * A_path.getLength(), mCurrentPath, new IEntityModifierListener() {

			public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {

			}

			public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {

			}
		}, new PathModifier.IPathModifierListener() {

			public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity,
					int pWaypointIndex) {

				
					switch (A_path.getDirectionToNextStep(pWaypointIndex)) {
					case DOWN:
						player.animate(ANIMATE_DURATION, 3, 5, true);
						break;

					case RIGHT:
						player.animate(ANIMATE_DURATION, 6, 8, true);
						break;

					case UP:
						player.animate(ANIMATE_DURATION, 0, 2, true);
						break;

					case LEFT:
						player.animate(ANIMATE_DURATION, 9, 11, true);
						break;

					default:
						break;
					}
				
				// Keep the waypointIndex in a Global Var
				mWaypointIndex = pWaypointIndex;

			}

			public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity, int pWaypointIndex) {
			}

			public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {
				// Set a global var
				isWalking = true;
			}

			public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
				// Stop walking and set A_path to null
				isWalking = false;
				A_path = null;
				player.stopAnimation();
			}

		}, EaseLinear.getInstance());

		player.registerEntityModifier(mMoveModifier);
	}

}
